初心者の方からの質問 MQL5 MT5 MetaTrader 5 - ページ 728

 

こんにちは。MetaTraider 4でExpert Advisorを書いていたのですが。というか、書き方を覚えようとしていたのです。知らないことだらけです。それをMetaTraider 5に移植することにしたのですが、これがちょっと違うことがわかりました。一般的に、私は別のExpert Advisorを取りました。分解してみました。ベットを開くためのコードをコピーしてみました。エラーは出ないのですが、思うように動作しません。正しく動かすのを手伝ってください。

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


そして、それが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:

こんにちは。MetaTraider 4でExpert Advisorを書いていたのですが。というか、書き方を覚えようとしていたのです。知らないことだらけです。MetaTraider 5に転送することにしたのですが、これがちょっと違うことがわかりました。一般的に、私は別のExpert Advisorを取りました。分解してみました。ベットを開くためのコードをコピーしてみました。エラーは出ないのですが、思うように動作しません。右の転送を助けてください。


コードは次のようになります(ただし、取引口座のポジションの合計数(PositionTotal)のチェックがあるので注意が必要です)。

   if(PositionsTotal()==0)

つまり、与えられたシンボルと与えられたMagicに対して、正確にいくつのポジションがあるかをチェックすることはない(ちなみに、Magicは全く設定されていない))

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

また、OrderSend 操作の結果は、bool 型 である。

残高を格納するためにスタティック変数を使用しました

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

- つまり、変数 "Balance "は、その後のOnTick()の到着時に再作成されませんが、前のティックの値を記憶しています。

ファイル:
TestEA.mq5  10 kb
 

私ならこう書くけれど。

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

これです。

  1. ストップロスは「4倍」pipsで設定されています。つまり、EURUSDとUSDJPYの両方で正しく機能します。
  2. CSymbolInfo trade クラスのオブジェクト "m_symbol" を価格取得のために使用する。
  3. 与えられたシンボルと与えられたMagicのポジションの総量をチェックします。
  4. ロットが変更された場合、事前に「LotCheck」でチェックし、修正する。
  5. CTrade トレードクラスの "m_trade "オブジェクトのメソッドを使用してトレード操作を行う。
  6. 取引結果のチェック(基本チェックと配置結果の2段階)。

追加されました。

ストラテジーテスターで1回だけ実行したところ、非常に興味深い結果が得られました。

テスター


ファイル:
TestEA.mq5  14 kb
 
Vladimir Karputov:

私ならこう書くけれど。

このとき、SymbolInfoTick()が新鮮なデータを返さない可能性があるので、m_symbol.RefreshRates()を使うことはお勧めしません。そして、もし開発者がこのスレッドを読んでいたら、もう一度、SymbolInfoTick()がめちゃくちゃに なるのに、SBクラスでまだ使われているという事実に注意を促してください!
 
こんにちは!自習のためにMQL5で緑赤キャンドル戦略を使った多通貨Expert Advisorを 作ることにしました
基本機能は実装されていますが、「Invalid price」などのエラーが 出続けています。考えられる原因を排除するためにいくつかのチェックを追加し、確かに正しい値に設定しましたが、エラーは消えません。私自身、どっちつかずなんです。どこが間違いなのか教えてください。ソースコードを添付します。
ファイル:
 
NickWelder:
こんにちは!私は自習のためにMQL5で緑赤キャンドル戦略に基づいた多通貨Expert Advisorを作成することにしました。
基本的な機能は実装していますが、「価格が無効です」などのエラーが出続けます。考えられる原因を排除するためのチェックを追加し、それぞれ、既知の正しい値に設定しましたが、エラーは消えません。私自身、どっちつかずなんです。どこが間違いなのか教えてください。ソースコードを添付します。

取引操作を 行う前に、取引クラスの CSymbolInfo オブジェクトの価格を更新する必要があります。私のモノラルプロジェクト(シンボルが1つしかない)では、この機能を使っています。

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

と使用方法 - 価格の更新に成功しなかった場合はそのまま終了し、価格の更新に成功した場合は、取引操作が行われます。

//--- 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(
 
ウラジーミル・カルプトフ さん、ありがとうございます。すべて成行注文で動きました。
 

このデザインに代わる、素敵で「簡単」な解決策は何でしょうか?

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

今はこんな感じですが、私の好みからすると「重すぎる」んです。

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:

このデザインに代わる、素敵で「簡単」な解決策は何でしょうか?

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

今はこんな感じですが、私の好みからすると「重すぎる」んです。

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);
}
こんな感じ(@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);
}
//+------------------------------------------------------------------+
誰かがどこかに書いていましたが、選択した行で次のようにすると良いそうです:if(time>=last_bar) res=0;

正直なところ、確認していないんですよねー。チェックし、結果を書いてください。
 
Vitaly Muzichenko:

このデザインに代わる、素敵で「簡単」な解決策は何でしょうか?

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

今はこんな感じですが、私の好みからすると「重すぎる」んです。

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);
}
私の解答がどれだけ「軽い」かは分かりませんが、こうしてみてください。https://www.mql5.com/ru/forum/160945#comment_4053382。
Как получить номер бара по времени входа в позицию?
Как получить номер бара по времени входа в позицию?
  • www.mql5.com
Приветствую! Пишу трейлинг, который проходится по барам начиная от времени входа в позицию...
理由: