記事"MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第25部): 取引サーバから返されたエラーの処理"についてのディスカッション

 

新しい記事 MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第25部): 取引サーバから返されたエラーの処理 はパブリッシュされました:

サーバに取引注文を送信した後は、エラーコードやエラーがないことを確認する必要があります。本稿では、取引サーバによって返されるエラーの処理について考察し、未決取引リクエストを作成する準備をします。

ビルド2201以降のMetaTrader 5の最新バージョンでは、テスターはテストが実行される銘柄のパラメータを設定する機能を備えています。したがって、銘柄に取引制限を設定し、銘柄制限が検出されたときにライブラリの動作をテストすることができます。

銘柄設定ウィンドウを呼び出すには、テストされた時間枠の選択の右側にあるボタンをクリックします。

銘柄に対してのみロングポジションを開くことを許可し、同時に開かれたポジションと一方向の未決注文のボリューム制限を0.5に設定します。

したがって、ロングポジションのみを使用することができ、市場での買いポジションと注文の最大合計ボリュームは0.5ロット以下になります。言い換えると、0.1のロットでポジションを開く場合、5つのポジションのみを開くか、単一の買い指値注文を発行して4つのポジションを開くことができます。


より信頼性を高めるために、指定された利益を超えたときにポジションの自動決済を無効にすることができます。ただし、ショートポジションを開けなかったことがわかり、銘柄では買いポジションのみが許可されているという警告を受け取りました。さらに、総ボリュームが0.5ロットを超えるポジションを複数開こうとすると、ポジションと注文の最大総ボリュームを一方向に超えたためにポジションを開けないというメッセージが表示されます。

作者: Artyom Trishkin

 
こんにちは!ライブラリの最新版とExpert Part_23をダウンロードし、テスターでビジュアルモードを使用したところ、成行注文はオープンされましたが、すべての未決注文はオープンされませんでした。
ジャーナルに「2019.10.27 10:13:32.157 2019.09.23 10:00:02 failed sell stop limit 2.00 RTS-12.19 at 135750 (135800) sl: 135900 tp: 135600 [Invalid expiration].

取引所のシンボル、ブローカーOtkritie、バージョン5.00ビルド2190。

すみません、その23で議論の続きがあったのですが、巻き込まれて見逃してしまいました。とにかく、私はバージョン25をダウンロードし、問題は残っています。第23回のディスカッションでは、onInit'eのある行の後に追加行を挿入する必要があると書かれていましたが、緑色でハイライトされているこれらの行は、第23回でも第25回でもonInit'eにはありません:

//--- EAグローバル変数の 設定

prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";

for(int i=0;i<TOTAL_BUTT;i++)

{

butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);

butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);

}

lot=NormaliseLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));

magic_number=InpMagic;

stoploss=InpStopLoss;

takeprofit=InpTakeProfit;

distance_pending=InpDistance;

distance_stoplimit=InpDistanceSL;

スリッページ=InpSlippage;

trailing_stop=InpTrailingStop*Point();

trailing_step=InpTrailingStep*Point();

trailing_start=InpTrailingStart;

stoploss_to_modify=InpStopLossModify;

takeprofit_to_modify=InpTakeProfitModify;


//--- DoEasyライブラリの初期化

OnInitDoEasy();

//--- Expert Advisorの未公開グラフィカル・オブジェクトのチェックと削除

if(IsPresentObects(prefix))

ObjectsDeleteAll(0,prefix);


//--- ボタンバーを作成する

if(!CreateButtons(InpButtShiftX,InpButtShiftY))

return INIT_FAILED;

//--- 末尾の起動ボタンの状態を設定する

ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);

//tr.SetCorrectTypeExpiration();

engine.TradingSetCorrectTypeExpiration();

engine.TradingSetCorrectTypeFilling();

//--- マクロ置換による標準サウンドと説明によるカスタムサウンドの再生チェック

engine.PlaySoundByDescription(SND_OK);

Sleep(600);

engine.PlaySoundByDescription(TextByLanguage("The sound of a falling coin 2", "The sound of a falling coin 2"));


//---

return(INIT_SUCCEEDED);

 
Alexander:
こんにちは!最新版のライブラリとExpert Part_23をダウンロードし、テスターでビジュアルモードとマーケットモードを設定しました。
ジャーナルに「2019.10.27 10:13:32.157 2019.09.23 10:00:02 failed sell stop limit 2.00 RTS-12.19 at 135750 (135800) sl: 135900 tp: 135600 [Invalid expiration].

取引所のシンボル、ブローカーOtkritie、バージョン5.00ビルド2190。

すみません、その23で議論の続きがあったのですが、巻き込まれて見逃してしまいました。とにかく、私はバージョン25をダウンロードし、問題は残っています。第23回の議論では、ある行の後にonInit'eに追加行を挿入する必要があると書かれていましたが、あなたが緑色で強調されたこれらの行は、第23回のバージョンにも第25回のバージョンにもonInit'eには全くありません:

第25条のテストEA、"TestDoEasyPart25.mq5 "を使っていますか?

 
バージョン23のonInitに私が追加した関数を挿入しましたが、バージョン25を使用したところ、バージョン23であなたが緑色で強調した行がなく、バージョン25も23のようには動作しませんでした。
 
Alexander:
バージョン23のonInitに私が追加した関数を挿入したのですが、バージョン25を使用したところ、バージョン23であなたが緑色で強調表示した行がなく、バージョン25は23と同様に動作しませんでした。

どの緑色で強調されている行のことを言っているのか理解できません。

そして、他の記事のテストEAを使用しないでください - 各記事にはテスト用の独自のEAが付属しています - あなたはそれを使用し、他の記事からではなく、正しいテストEAに関連して発見したエラーを報告する必要があります。

 

前回の記事に関連して、すみません:

こんにちは!ライブラリの最新版とExpert Part_25をダウンロードし、テスターでビジュアルモードを設定しました。

2019.11.21 12:59:20.689 2019.11.18 10:00:02 failed sell stop limit 2.00 Si-12.19 at 63972 (64022) sl: 64072 tp: 63972 [Invalid expiration]and 2019.11.21 12:59:20.689 2019.11.18 10:00:02 Trade attempt #3.エラー : リクエストの注文有効 期限が無効です。

取引所シンボル、ブローカーOtkritie、バージョン5.00ビルド2190。
 
Alexander:

前回の記事に関連して、すみません:

こんにちは!最新版のライブラリとExpert Part_25をダウンロードして、テスターにビジュアルモードとマーケットモードを入れました。

2019.11.21 12:59:20.689 2019.11.18 10:00:02 failed sell stop limit 2.00 Si-12.19 at 63972 (64022) sl: 64072 tp: 63972 [Invalid expiration]and 2019.11.21 12:59:20.689 2019.11.18 10:00:02 Trade attempt #3.エラー : リクエストの注文有効 期限が無効です。

取引所シンボル、ブローカーOtkritie、バージョン5.00ビルド2190。

わかりました、ありがとうございます。

エラーが発生したシンボルの指定があるスクリーンショットをここに添付できますか?

 
Si-12.19仕様のスクリーンショットがファイルされている。
ファイル:
 
Alexander:
ファイル中のSi-12.19仕様の画面。

このバージョンのライブラリでも、次回の ライブラリでもそうですが、注文の充填タイプと有効期限タイプをチェックしそびれていました。次回(27日)の記事で訂正します。

今のところ提案できるのは、取引リクエストを送信する際に、有効期限タイプを明示的に指定することです。例えば、売り指値のペンディング注文を出すには、テスト用Expert Advisorにそれを追加する必要があります

//--- BUTT_SELL_LIMIT ボタンが押された場合: SellLimit を設定する。
else if(button==EnumToString(BUTT_SELL_LIMIT))
  {
   //--- 売り指値注文を設定する
   engine.PlaceSellLimit(lot,Symbol(),distance_pending,stoploss,takeprofit,magic,TextByLanguage(「保留中の売りリミット,"Pending order SellLimit"),0,ORDER_TIME_DAY);
  }

そして、保留注文を設定 するメソッドの呼び出しを含むすべての行で同じことを行います。

 

アルテム、君の仕事ぶりには感謝している。

正直なところ、マジックナンバーを合成する意味がよくわかりませんでした。

EAの取引を異なるマジックナンバーを持ついくつかのグループに分けるとします。

古典的なアプローチでは、その後注文を調べてマジックナンバーを比較し、その結果をグループ間で分配します。

ライブラリでは、このような状況はあまり変化しないと理解しています。それとも、他に何か影響があるのでしょうか?


それから、あなたのライブラリには決定的に欠けている機能があります。

あるパラメータ(マジック、シンボル、注文の種類)の集合に対する利益の総計はいくらか、という質問に答えなければならないことがよくあります。例えば、ロットの集計。損益分岐点レベル。取引回数

これらの集計値はあらゆる場所で繰り返し必要とされるものであり、新しい手法のたびにサンプルで計算するのは明らかにやりすぎである。

集計値のセットを用意し、それぞれをサンプリング基準(シンボル、タイプ、マジク、グループ番号)で構成し、CEngineでそれらにアクセスできるようにし、Refreshで一度だけ更新できるようにすれば素晴らしいでしょう。

もしこのような改良の予定がなければ、最終的な結論を出して共有することもできるのですが......。しかし、私たちのコードスタイルが大きく異なるだけで、この作品は異質なものに見えるだろう。

 
rigal:

アルテム、君の仕事ぶりには感謝している。

正直なところ、合成マジックの意味がよく分からなかったんだ...。

Expert Advisorのトレードをマジックナンバーの異なるいくつかのグループに分けたいとします。

古典的なアプローチでは、その後注文を調べてマジックナンバーを比較し、その結果をグループ間で分配します。

ライブラリでは、このような状況はあまり変化しないと理解しています。それとも、他に何か影響があるのでしょうか?


そして、あなたのライブラリには決定的に欠けている機能のあるレイヤーもあります。

あるパラメータ(マジック、シンボル、オーダー・タイプ)の集合に対する利益の集計はどうなるのか、という質問に答える必要があることがよくあります。例えば、ロットの集計。損益分岐点レベル。そして取引回数

これらの集計値はあらゆる場所で繰り返し必要とされるものであり、新しい手法のたびにサンプルで計算するのは明らかにやりすぎである。

集計値のセットを用意し、それぞれにサンプリング基準(シンボル、タイプ、マジック、グループ番号)を設定し、CEngineでそれらにアクセスできるようにし、Refreshで一度だけ更新できるようにすれば素晴らしいでしょう。

もしこのような改良の予定がないのであれば、最終的な結論を出して共有することもできますが......。しかし、私たちのコードスタイルが大きく異なるだけで、この作品は異質なものに見えるだろう。

マジックナンバーに記録される情報について:

を使えば、グループごとに異なるマジックを使うことができる。例えば、アドバイザーのマジックが123の場合、最初のグループのマジックは124、2番目のグループのマジックは125、3番目のグループのマジックは126、といった具合だ。
各サブグループの番号はマジックナンバーの値に直接格納されます。次に、EAのマジックナンバーもグループ識別子ですが、MagicIDという独立したグループ(EAのマジックナンバー識別子)に入ります。さらに2つのグループがある。それぞれに15のサブグループがある。そして、それぞれのサブグループは独自の識別子を持つことができる。

これによって、グループを扱う際の柔軟性が 増す。

例えば、未決注文のグリッドを価格の後ろに移動させたい場合、サブグループ1のグループ1に追加します。グループ1は価格の後ろに移動します。サブグループ1はMAに沿って移動します。次に、パラボリックSARによって価格の後ろに移動する注文(グループ1)を移動させます。サブグループ2を指定します。すると、グループ1は価格の後に移動しますが、サブグループ1はMAで移動し、サブグループ2はパラボリックSARで移動します。

注文はトリガーされ、ポジションに変わります。ストップロスを修正するために独自のグループを設定し、異なる値で修正するためにこのグループに独自のサブグループを設定することができます。修正アルゴリズムはサブグループに書かれている。

一般的に - 空想の飛行。簡単なマジックを使うこともできますが、異なるグループを追跡するロジックを自分で考えなければなりません。

つ目の質問について:

CSelectというクラスがあります。これはプログラムから利用可能で、既存のすべてのコレクション(Account、Event、Order、Symbol)からの選択と検索のメソッドを提供します。

各コレクションのオブジェクトを、すべての条件に基づいてリストに選択することができます。作成されたリストでは、基準を絞り込んで再選択することができ、選択基準の最大値と最小値を見つけることができます。

しかし、すべてのコレクションのすべてのプロパティに迅速かつ便利にアクセスし、それらを検索するためのさらなるユーザー機能(ずっと後)があります。

しかし、今のところは、CSelectを通してのみ、必要なときに利用できる。このクラスは静的なので、メソッドへのアクセスは ":::" 経由で行う。例えば、CSelect::ByOrderProperty()。

そうそう、ちなみに、テストEAの右側のプログラムには、これを使う例があります - たとえば、その末尾の関数で:

//+------------------------------------------------------------------+
//| 最も遠い保留中の注文を検索する。
//+------------------------------------------------------------------+
void TrailingOrders(void)
  {
   MqlTick tick;
   if(!SymbolInfoTick(Symbol(),tick))
      return;
   double stop_level=StopLevel(Symbol(),2)*Point();
//--- セットされたすべての注文のリストを取得する
   CArrayObj* list=engine.GetListMarketPendings();
   //--- 現在のシンボルによる注文のみをリストから選択する。
   list=CSelect::ByOrderProperty(list,ORDER_PROP_SYMBOL,Symbol(),EQUAL);
//--- リストから買い方向の注文のみを選択する。
   CArrayObj* list_buy=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_BUY,EQUAL);
   //--- 価格からの距離(pips)でソート (利益(pips)でソート)
   list_buy.Sort(SORT_BY_ORDER_PROFIT_PT);
   //--- 買い方向で最大の距離を持つ注文のインデックスを取得する。
   int index_buy=CSelect::FindOrderMax(list_buy,ORDER_PROP_PROFIT_PT);
   if(index_buy>WRONG_VALUE)
     {
      COrder* buy=list_buy.At(index_buy);
      if(buy!=NULL)
        {
         //--- 注文が価格(BuyLimit)より下に設定され、価格の後ろに「持ち上げる」必要がある場合。
         if(buy.TypeOrder()==ORDER_TYPE_BUY_LIMIT)
           {
            //--- 新しい注文設定価格とストップ・レベルを新しい価格から計算する。
            double price=NormalizeDouble(tick.ask-trailing_stop,Digits());
            double sl=(buy.StopLoss()>0 ? NormalizeDouble(price-(buy.PriceOpen()-buy.StopLoss()),Digits()) : 0);
            double tp=(buy.TakeProfit()>0 ? NormalizeDouble(price+(buy.TakeProfit()-buy.PriceOpen()),Digits()) : 0);
            計算された価格がStopLevelの距離より低い場合、Ask注文の設定価格から延期する(StopLevelの距離が観察される) //--- 計算された価格がStopLevelの距離より低い場合、Ask注文の設定価格から延期する。
            if(price<tick.ask-stop_level) 
              {
               //--- 計算された価格が、注文設定価格から延期されたトロール・ステップよりも高い場合、注文設定価格を修正する。
               if(price>buy.PriceOpen()+trailing_step)
                 {
                  engine.ModifyOrder((ulong)buy.Ticket(),price,sl,tp,-1);
                 }
              }
           }
         //--- 注文が価格(BuyStopとBuyStopLimit)より上に設定され、価格の後ろに「下げる」必要がある場合。
         else
           {
            //--- 新しい注文設定価格とストップ・レベルを新しい価格から計算する。
            double price=NormalizeDouble(tick.ask+trailing_stop,Digits());
            double sl=(buy.StopLoss()>0 ? NormalizeDouble(price-(buy.PriceOpen()-buy.StopLoss()),Digits()) : 0);
            double tp=(buy.TakeProfit()>0 ? NormalizeDouble(price+(buy.TakeProfit()-buy.PriceOpen()),Digits()) : 0);
            //--- 計算された価格がStopLevelの距離よりも高い場合、Ask注文の設定価格から延期される(StopLevelの距離が観察される)。
            if(price>tick.ask+stop_level) 
              {
               //--- 計算された価格が、注文設定価格から延期されたトロール・ステップよりも低い場合、注文設定価格を修正する。
               if(price<buy.PriceOpen()-trailing_step)
                 {
                  engine.ModifyOrder((ulong)buy.Ticket(),price,sl,tp,-1);
                 }
              }
           }
        }
     }
//--- リストから売り方向の注文のみを選択する。
   CArrayObj* list_sell=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_SELL,EQUAL);
   //--- 価格からの距離(pips)でソート (利益(pips)でソート)
   list_sell.Sort(SORT_BY_ORDER_PROFIT_PT);
   //--- 最大の距離を持つセル方向のオーダーのインデックスを取得する。
   int index_sell=CSelect::FindOrderMax(list_sell,ORDER_PROP_PROFIT_PT);
   if(index_sell>WRONG_VALUE)
     {
      COrder* sell=list_sell.At(index_sell);
      if(sell!=NULL)
        {
         //--- もし注文が価格(SellLimit)より上に設定されていて、価格の後ろに「下げる」必要がある場合。
         if(sell.TypeOrder()==ORDER_TYPE_SELL_LIMIT)
           {
            //--- 新しい注文設定価格とストップ・レベルを新しい価格から計算する。
            double price=NormalizeDouble(tick.bid+trailing_stop,Digits());
            double sl=(sell.StopLoss()>0 ? NormalizeDouble(price+(sell.StopLoss()-sell.PriceOpen()),Digits()) : 0);
            double tp=(sell.TakeProfit()>0 ? NormalizeDouble(price-(sell.PriceOpen()-sell.TakeProfit()),Digits()) : 0);
            計算された価格がStopLevelの距離より高い場合、Bid注文の設定価格から延期される(StopLevelの距離が観察される) //--- 計算された価格がStopLevelの距離より高い場合、Bid注文の設定価格から延期される。
            if(price>tick.bid+stop_level) 
              {
               //--- 計算された価格が、注文設定価格から延期されたトロール・ステップよりも低い場合、注文設定価格を修正する。
               if(price<sell.PriceOpen()-trailing_step)
                 {
                  engine.ModifyOrder((ulong)sell.Ticket(),price,sl,tp,-1);
                 }
              }
           }
         //--- 注文が価格より下に設定され(SellStopとSellStopLimit)、価格の後ろで "持ち上げられる "必要がある場合。
         else
           {
            //--- 新しい注文設定価格とストップ・レベルを新しい価格から計算する。
            double price=NormalizeDouble(tick.bid-trailing_stop,Digits());
            double sl=(sell.StopLoss()>0 ? NormalizeDouble(price+(sell.StopLoss()-sell.PriceOpen()),Digits()) : 0);
            double tp=(sell.TakeProfit()>0 ? NormalizeDouble(price-(sell.PriceOpen()-sell.TakeProfit()),Digits()) : 0);
            計算された価格がStopLevelの距離より低い場合、Bid注文の設定価格から延期される(StopLevelの距離が観察される) //--- 計算された価格がStopLevelの距離より低い場合、Bid注文の設定価格から延期される。
            if(price<tick.bid-stop_level) 
              {
               //--- 計算された価格が、注文設定価格から延期されたトロール・ステップよりも高い場合、注文設定価格を修正する。
               if(price>sell.PriceOpen()+trailing_step)
                 {
                  engine.ModifyOrder((ulong)sell.Ticket(),price,sl,tp,-1);
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+