ゼロから始めるEA開発Part8 エラー時の処理
前回は「移動平均」と「値幅」を使ったシステム構築を行いまいした。
結構、良い物ができましたね!
今回は「エラーが発生した場合の処理」についてです。
エラー時の処理は必ずしも必要なものではありませんが、エラー発生時の原因追求に役に立ちますので、「ご自身で作ったEAを使用する(他の人が使うことは無い)」としても入れておいた方が良いでしょう。
オープンエラーを取得・表示する
発注を出す関数「OrderSend」は戻り値にチケット番号というポジション1つ1つに自動で振られる番号を返します。
ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue);
このチケット番号が正しく振られていればオープン成功、失敗した場合には-1が返ります。
つまり、このチケット番号をチェックすることで「エラーが発生したかどうか判断できる」ということです。
if(ticket < 0) { Print("OrderSend Error : " + GetErrorMessage(GetLastError())); }
エラーが発生していたらPrintという関数を使ってエキスパートログにエラーメッセージを出力します。
Print関数はPrint(“文字列”); と書くだけで、ログに文字列を出力できる便利な関数です。
GetErrorMessage関数というのは今回、新たに作った関数でエラーコードを渡すとエラーメッセージを返すようになっています。(GetErrroMessage関数は非常に長いので「ソースコード全文」でご確認ください。)
なお、「エラーが発生した場合にはすぐに分かるようにしたい」場合にはPrint関数ではなくAlert関数を使ってみてください。
使い方はPrintと同じで、Alert(“文字列”); とするだけです。(Alertはポップアップでメッセージが表示されます)
※Alertはバックテスト時無効のため、バックテストで動作確認する場合にはPrintにしておいてください。
クローズエラーを取得・表示する
OrderCloseの戻り値はtrue/falseになります。
trueが返ってくれば正常終了。falseが返ってきたらエラーです。
result = OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrBlue); if(!result) { Print("OrderClose Error : " + GetErrorMessage(GetLastError())); }
if文ではtrueかfalseを判断する場合、==trueを省略できます。
if(result)
と
if(result == true)
は同じ意味です。
否定の演算子!を付けるとfalseかどうか判断できます。つまり…
if(!result)
と
if(result == false) あるいは if(result != true)
は同じ意味になります。
当連載ではあまり省略形を使わないように書いていますが、if文のtrue/falseに関しては省略で書かれることの方が多いため、今後もこの形で記載します。
以下、修正したソースコードの全文です。
//+------------------------------------------------------------------+ //| ZeroCreatePart2.mq4 | //| | //| | //+------------------------------------------------------------------+ #property copyright "" #property link "" #property version "1.00" #property strict input int Magic = 123465; input double Lots = 0.1; input int Slippage = 2; input string OrdersComment = "ZeroCreate"; input int StopLoss = 200; input int TakeProfit = 400; input int EMAPeriod = 20; input double HeightPercent = 0.5; datetime OpenBarTime = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { double ema = iMA(Symbol(),0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); if(OrdersTotal() == 0) { double barHeight = MathAbs(Close[0] - Open[0]); double percentage = (barHeight / Ask) * 100; double stopLoss = 0; double takeProfit = 0; int ticket = 0; if(percentage > HeightPercent && Time[0] != OpenBarTime) { if(Ask > ema) { stopLoss = Ask - StopLoss * Point; takeProfit = Bid + TakeProfit * Point; ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue); } if(ema > Bid) { stopLoss = Bid + StopLoss * Point; takeProfit = Ask - TakeProfit * Point; ticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrRed); } if(ticket < 0) { Print("OrderSend Error : " + GetErrorMessage(GetLastError())); } OpenBarTime = Time[0]; } } if(OrdersTotal() > 0) { for(int i=0; i<=OrdersTotal()-1; i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break; bool result = true; if(OrderType() == OP_BUY && ema > Ask) { result = OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrBlue); } else if(OrderType() == OP_SELL && Bid > ema) { result = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrRed); } if(!result) { Print("OrderClose Error : " + GetErrorMessage(GetLastError())); } } } } string GetErrorMessage(int errorCode) { switch(errorCode) { case ERR_NO_ERROR: return ("No error returned."); case ERR_NO_RESULT: return ("No error returned, but the result is unknown."); case ERR_COMMON_ERROR: return ("Common error."); case ERR_INVALID_TRADE_PARAMETERS: return ("Invalid trade parameters."); case ERR_SERVER_BUSY: return ("Trade server is busy."); case ERR_OLD_VERSION: return ("Old version of the client terminal."); case ERR_NO_CONNECTION: return ("No connection with trade server."); case ERR_NOT_ENOUGH_RIGHTS: return ("Not enough rights."); case ERR_TOO_FREQUENT_REQUESTS: return ("Too frequent requests."); case ERR_MALFUNCTIONAL_TRADE: return ("Malfunctional trade operation."); case ERR_ACCOUNT_DISABLED: return ("Account disabled."); case ERR_INVALID_ACCOUNT: return ("Invalid account."); case ERR_TRADE_TIMEOUT: return ("Trade timeout."); case ERR_INVALID_PRICE: return ("Invalid price."); case ERR_INVALID_STOPS: return ("Invalid stops."); case ERR_INVALID_TRADE_VOLUME: return ("Invalid trade volume."); case ERR_MARKET_CLOSED: return ("Market is closed."); case ERR_TRADE_DISABLED: return ("Trade is disabled."); case ERR_NOT_ENOUGH_MONEY: return ("Not enough money."); case ERR_PRICE_CHANGED: return ("Price changed."); case ERR_OFF_QUOTES: return ("Off quotes."); case ERR_BROKER_BUSY: return ("Broker is busy."); case ERR_REQUOTE: return ("Requote."); case ERR_ORDER_LOCKED: return ("Order is locked."); case ERR_LONG_POSITIONS_ONLY_ALLOWED: return ("Long positions only allowed."); case ERR_TOO_MANY_REQUESTS: return ("Too many requests."); case ERR_TRADE_MODIFY_DENIED: return ("Modification denied because an order is too close to market."); case ERR_TRADE_CONTEXT_BUSY: return ("Trade context is busy."); case ERR_TRADE_EXPIRATION_DENIED: return ("Expirations are denied by broker."); case ERR_TRADE_TOO_MANY_ORDERS: return ("The amount of opened and pending orders has reached the limit set by a broker."); case ERR_NO_MQLERROR: return ("No error."); case ERR_WRONG_FUNCTION_POINTER: return ("Wrong function pointer."); case ERR_ARRAY_INDEX_OUT_OF_RANGE: return ("Array index is out of range."); case ERR_NO_MEMORY_FOR_CALL_STACK: return ("No memory for function call stack."); case ERR_RECURSIVE_STACK_OVERFLOW: return ("Recursive stack overflow."); case ERR_NOT_ENOUGH_STACK_FOR_PARAM: return ("Not enough stack for parameter."); case ERR_NO_MEMORY_FOR_PARAM_STRING: return ("No memory for parameter string."); case ERR_NO_MEMORY_FOR_TEMP_STRING: return ("No memory for temp string."); case ERR_NOT_INITIALIZED_STRING: return ("Not initialized string."); case ERR_NOT_INITIALIZED_ARRAYSTRING: return ("Not initialized string in an array."); case ERR_NO_MEMORY_FOR_ARRAYSTRING: return ("No memory for an array string."); case ERR_TOO_LONG_STRING: return ("Too long string."); case ERR_REMAINDER_FROM_ZERO_DIVIDE: return ("Remainder from zero divide."); case ERR_ZERO_DIVIDE: return ("Zero divide."); case ERR_UNKNOWN_COMMAND: return ("Unknown command."); case ERR_WRONG_JUMP: return ("Wrong jump."); case ERR_NOT_INITIALIZED_ARRAY: return ("Not initialized array."); case ERR_DLL_CALLS_NOT_ALLOWED: return ("DLL calls are not allowed."); case ERR_CANNOT_LOAD_LIBRARY: return ("Cannot load library."); case ERR_CANNOT_CALL_FUNCTION: return ("Cannot call function."); case ERR_EXTERNAL_CALLS_NOT_ALLOWED : return ("EA function calls are not allowed."); case ERR_NO_MEMORY_FOR_RETURNED_STR: return ("Not enough memory for a string returned from a function."); case ERR_SYSTEM_BUSY: return ("System is busy."); case ERR_INVALID_FUNCTION_PARAMSCNT: return ("Invalid function parameters count."); case ERR_INVALID_FUNCTION_PARAMVALUE: return ("Invalid function parameter value."); case ERR_STRING_FUNCTION_INTERNAL: return ("String function internal error."); case ERR_SOME_ARRAY_ERROR: return ("Some array error."); case ERR_INCORRECT_SERIESARRAY_USING: return ("Incorrect series array using."); case ERR_CUSTOM_INDICATOR_ERROR: return ("Custom indicator error."); case ERR_INCOMPATIBLE_ARRAYS: return ("Arrays are incompatible."); case ERR_GLOBAL_VARIABLES_PROCESSING: return ("Global variables processing error."); case ERR_GLOBAL_VARIABLE_NOT_FOUND: return ("Global variable not found."); case ERR_FUNC_NOT_ALLOWED_IN_TESTING: return ("Function is not allowed in testing mode."); case ERR_FUNCTION_NOT_CONFIRMED: return ("Function is not confirmed."); case ERR_SEND_MAIL_ERROR: return ("Mail sending error."); case ERR_STRING_PARAMETER_EXPECTED: return ("String parameter expected."); case ERR_INTEGER_PARAMETER_EXPECTED: return ("Integer parameter expected."); case ERR_DOUBLE_PARAMETER_EXPECTED: return ("Double parameter expected."); case ERR_ARRAY_AS_PARAMETER_EXPECTED: return ("Array as parameter expected."); case ERR_HISTORY_WILL_UPDATED: return ("Requested history data in updating state."); case ERR_TRADE_ERROR: return ("Some error in trade operation execution."); case ERR_END_OF_FILE: return ("End of a file."); case ERR_SOME_FILE_ERROR: return ("Some file error."); case ERR_WRONG_FILE_NAME: return ("Wrong file name."); case ERR_TOO_MANY_OPENED_FILES: return ("Too many opened files."); case ERR_CANNOT_OPEN_FILE: return ("Cannot open file."); case ERR_INCOMPATIBLE_FILEACCESS: return ("Incompatible access to a file."); case ERR_NO_ORDER_SELECTED: return ("No order selected."); case ERR_UNKNOWN_SYMBOL: return ("Unknown symbol."); case ERR_INVALID_PRICE_PARAM: return ("Invalid price."); case ERR_INVALID_TICKET: return ("Invalid ticket."); case ERR_TRADE_NOT_ALLOWED: return ("Trade is not allowed."); case ERR_LONGS_NOT_ALLOWED: return ("Longs are not allowed."); case ERR_SHORTS_NOT_ALLOWED: return ("Shorts are not allowed."); case ERR_OBJECT_ALREADY_EXISTS: return ("Object already exists."); case ERR_UNKNOWN_OBJECT_PROPERTY: return ("Unknown object property."); case ERR_OBJECT_DOES_NOT_EXIST: return ("Object does not exist."); case ERR_UNKNOWN_OBJECT_TYPE: return ("Unknown object type."); case ERR_NO_OBJECT_NAME: return ("No object name."); case ERR_OBJECT_COORDINATES_ERROR: return ("Object coordinates error."); case ERR_NO_SPECIFIED_SUBWINDOW: return ("No specified subwindow."); case ERR_SOME_OBJECT_ERROR: return ("Some error in object operation."); default: return "Unknown error."; } } //+------------------------------------------------------------------+
エラーメッセージを返す関数がソースコードの半分以上を占めてしまいました(苦笑)
エラーメッセージは英語にしています。Mac版のMT4を使っている場合や、VPSが英語版Windowsの場合には「日本語が文字化けする」現象が発生するため私は日本語でメッセージ表示しませんが、「そのような環境で動かすことは無い」という場合には日本語のメッセージを出力するように書き換えてください。
※使用しているswitch文については説明しません… switchを使わなくてもif文で作れます。知っていると便利なことはありますので、知りたい方は “switch case” で検索してみてください。
さて、上記ソースコードをコンパイルすると今まで表示されていたwarning(警告)がなくなっています。
今まで警告が表示されていたのは「OrderSend関数」や「OrderClose関数」の戻り値をチェックした方が良いですよ!という警告でした。
今回の修正で戻り値をチェックするようにしたので警告が消えた、というわけです。
エラー処理の確認
バックテストでエラーが表示されるか確認してみましょう。
簡単な方法はパラメーター「StopLoss」に0を入れる方法です。0を入れると発注価格と同じ価格でストップロスを設定しようとするためエラーになります。
バックテスト時のエラーは操作履歴に表示されます。
Invalid stops(無効なストップ値)というエラーが表示されました。
バックテストで「クローズ時のエラー」を再現するのは…ちょっと思いつきません;;
※例えば、ソースコードを書き換えてOrderClose関数のクローズ価格に負の数を入れる…とか、強引な方法でエラーを発生させることはできます。
エラーメッセージ関数について
エラーメッセージ関数は他のEAを作成する場合にも使えます。
しかし、毎回この長い関数をコピー&ペーストするのは手間ですのでヘッダーファイルを作ってみましょう。
上部メニューのFile>Newか、Newボタンを選択してMQL Wizardを起動して下さい。
Include(*.mqh)を選択して次へ。
適当な名前を付けて「完了」をクリックします。
今回はErrorMessageという名前にしました。
入力例がコメントで書かれていますが邪魔なのでバッサリ削除。
そしてGetErrorMessage関数をカット&ペーストします。(元のプログラムには不要になるので切り取りました)
以下、ErrorMessage.mqhの全文です。
//+------------------------------------------------------------------+ //| ErrorMessage.mqh | //| | //| | //+------------------------------------------------------------------+ #property copyright "" #property link "" #property strict string GetErrorMessage(int errorCode) { switch(errorCode) { case ERR_NO_ERROR: return ("No error returned."); case ERR_NO_RESULT: return ("No error returned, but the result is unknown."); case ERR_COMMON_ERROR: return ("Common error."); case ERR_INVALID_TRADE_PARAMETERS: return ("Invalid trade parameters."); case ERR_SERVER_BUSY: return ("Trade server is busy."); case ERR_OLD_VERSION: return ("Old version of the client terminal."); case ERR_NO_CONNECTION: return ("No connection with trade server."); case ERR_NOT_ENOUGH_RIGHTS: return ("Not enough rights."); case ERR_TOO_FREQUENT_REQUESTS: return ("Too frequent requests."); case ERR_MALFUNCTIONAL_TRADE: return ("Malfunctional trade operation."); case ERR_ACCOUNT_DISABLED: return ("Account disabled."); case ERR_INVALID_ACCOUNT: return ("Invalid account."); case ERR_TRADE_TIMEOUT: return ("Trade timeout."); case ERR_INVALID_PRICE: return ("Invalid price."); case ERR_INVALID_STOPS: return ("Invalid stops."); case ERR_INVALID_TRADE_VOLUME: return ("Invalid trade volume."); case ERR_MARKET_CLOSED: return ("Market is closed."); case ERR_TRADE_DISABLED: return ("Trade is disabled."); case ERR_NOT_ENOUGH_MONEY: return ("Not enough money."); case ERR_PRICE_CHANGED: return ("Price changed."); case ERR_OFF_QUOTES: return ("Off quotes."); case ERR_BROKER_BUSY: return ("Broker is busy."); case ERR_REQUOTE: return ("Requote."); case ERR_ORDER_LOCKED: return ("Order is locked."); case ERR_LONG_POSITIONS_ONLY_ALLOWED: return ("Long positions only allowed."); case ERR_TOO_MANY_REQUESTS: return ("Too many requests."); case ERR_TRADE_MODIFY_DENIED: return ("Modification denied because an order is too close to market."); case ERR_TRADE_CONTEXT_BUSY: return ("Trade context is busy."); case ERR_TRADE_EXPIRATION_DENIED: return ("Expirations are denied by broker."); case ERR_TRADE_TOO_MANY_ORDERS: return ("The amount of opened and pending orders has reached the limit set by a broker."); case ERR_NO_MQLERROR: return ("No error."); case ERR_WRONG_FUNCTION_POINTER: return ("Wrong function pointer."); case ERR_ARRAY_INDEX_OUT_OF_RANGE: return ("Array index is out of range."); case ERR_NO_MEMORY_FOR_CALL_STACK: return ("No memory for function call stack."); case ERR_RECURSIVE_STACK_OVERFLOW: return ("Recursive stack overflow."); case ERR_NOT_ENOUGH_STACK_FOR_PARAM: return ("Not enough stack for parameter."); case ERR_NO_MEMORY_FOR_PARAM_STRING: return ("No memory for parameter string."); case ERR_NO_MEMORY_FOR_TEMP_STRING: return ("No memory for temp string."); case ERR_NOT_INITIALIZED_STRING: return ("Not initialized string."); case ERR_NOT_INITIALIZED_ARRAYSTRING: return ("Not initialized string in an array."); case ERR_NO_MEMORY_FOR_ARRAYSTRING: return ("No memory for an array string."); case ERR_TOO_LONG_STRING: return ("Too long string."); case ERR_REMAINDER_FROM_ZERO_DIVIDE: return ("Remainder from zero divide."); case ERR_ZERO_DIVIDE: return ("Zero divide."); case ERR_UNKNOWN_COMMAND: return ("Unknown command."); case ERR_WRONG_JUMP: return ("Wrong jump."); case ERR_NOT_INITIALIZED_ARRAY: return ("Not initialized array."); case ERR_DLL_CALLS_NOT_ALLOWED: return ("DLL calls are not allowed."); case ERR_CANNOT_LOAD_LIBRARY: return ("Cannot load library."); case ERR_CANNOT_CALL_FUNCTION: return ("Cannot call function."); case ERR_EXTERNAL_CALLS_NOT_ALLOWED : return ("EA function calls are not allowed."); case ERR_NO_MEMORY_FOR_RETURNED_STR: return ("Not enough memory for a string returned from a function."); case ERR_SYSTEM_BUSY: return ("System is busy."); case ERR_INVALID_FUNCTION_PARAMSCNT: return ("Invalid function parameters count."); case ERR_INVALID_FUNCTION_PARAMVALUE: return ("Invalid function parameter value."); case ERR_STRING_FUNCTION_INTERNAL: return ("String function internal error."); case ERR_SOME_ARRAY_ERROR: return ("Some array error."); case ERR_INCORRECT_SERIESARRAY_USING: return ("Incorrect series array using."); case ERR_CUSTOM_INDICATOR_ERROR: return ("Custom indicator error."); case ERR_INCOMPATIBLE_ARRAYS: return ("Arrays are incompatible."); case ERR_GLOBAL_VARIABLES_PROCESSING: return ("Global variables processing error."); case ERR_GLOBAL_VARIABLE_NOT_FOUND: return ("Global variable not found."); case ERR_FUNC_NOT_ALLOWED_IN_TESTING: return ("Function is not allowed in testing mode."); case ERR_FUNCTION_NOT_CONFIRMED: return ("Function is not confirmed."); case ERR_SEND_MAIL_ERROR: return ("Mail sending error."); case ERR_STRING_PARAMETER_EXPECTED: return ("String parameter expected."); case ERR_INTEGER_PARAMETER_EXPECTED: return ("Integer parameter expected."); case ERR_DOUBLE_PARAMETER_EXPECTED: return ("Double parameter expected."); case ERR_ARRAY_AS_PARAMETER_EXPECTED: return ("Array as parameter expected."); case ERR_HISTORY_WILL_UPDATED: return ("Requested history data in updating state."); case ERR_TRADE_ERROR: return ("Some error in trade operation execution."); case ERR_END_OF_FILE: return ("End of a file."); case ERR_SOME_FILE_ERROR: return ("Some file error."); case ERR_WRONG_FILE_NAME: return ("Wrong file name."); case ERR_TOO_MANY_OPENED_FILES: return ("Too many opened files."); case ERR_CANNOT_OPEN_FILE: return ("Cannot open file."); case ERR_INCOMPATIBLE_FILEACCESS: return ("Incompatible access to a file."); case ERR_NO_ORDER_SELECTED: return ("No order selected."); case ERR_UNKNOWN_SYMBOL: return ("Unknown symbol."); case ERR_INVALID_PRICE_PARAM: return ("Invalid price."); case ERR_INVALID_TICKET: return ("Invalid ticket."); case ERR_TRADE_NOT_ALLOWED: return ("Trade is not allowed."); case ERR_LONGS_NOT_ALLOWED: return ("Longs are not allowed."); case ERR_SHORTS_NOT_ALLOWED: return ("Shorts are not allowed."); case ERR_OBJECT_ALREADY_EXISTS: return ("Object already exists."); case ERR_UNKNOWN_OBJECT_PROPERTY: return ("Unknown object property."); case ERR_OBJECT_DOES_NOT_EXIST: return ("Object does not exist."); case ERR_UNKNOWN_OBJECT_TYPE: return ("Unknown object type."); case ERR_NO_OBJECT_NAME: return ("No object name."); case ERR_OBJECT_COORDINATES_ERROR: return ("Object coordinates error."); case ERR_NO_SPECIFIED_SUBWINDOW: return ("No specified subwindow."); case ERR_SOME_OBJECT_ERROR: return ("Some error in object operation."); default: return "Unknown error."; } }
次にこのファイルを元のファイルから呼び出せるように”include”します。
//+------------------------------------------------------------------+ //| ZeroCreatePart2.mq4 | //| | //| | //+------------------------------------------------------------------+ #property copyright "" #property link "" #property version "1.00" #property strict #include <ErrorMessage.mqh>
#include <mqhファイル名>と書くことでGetErrorMesssage関数が呼び出せるようになります。
他のEAを開発した場合もこの1文を書くだけでGetErrorMessage関数が使えますし、もしGetErrorMessage関数にバグがあってもErrorMessage.mqhファイルを修正するだけでincludeしているすべてのファイルの修正ができるため、よく使う関数はヘッダーファイルに分けてincludeするように作っておくと良いでしょう。
まとめ
今回、話の流れでヘッダーファイルの作成方法まで解説することになりましたので、かなりボリュームが増えてしまいました…。
エラーの処理は必須ではありませんが、エラー処理が実装されている方が望ましいのは間違いありません。
必要に応じてデバッグしやすいように変数の値などを出力させても良いと思います。
例)
Print("オープンエラー 発注価格=" + IntegerToString(price));
ご自分がわかりやすいように実装してみてください。
次回は「デバッグ」について解説します。
MT4のデバッグ機能は微妙に使いづらいのですが…
使い方を知っていればデバッグに便利な場面は少なくありません!
以上、初心者向けEA開発講座「自動売買システムを作ろう!ゼロから始めるEA開発Part8 エラー時の処理」でした。
コメント
こんばんは、
猛暑の毎日でございますが、いかがお過ごしでしょうか
毎度素敵な、プログラムありがとうございます。
こちらのブログを見て、素人ながら四苦八苦しながら学ばせていただいております。
今回は、エラーメッセージについてということなのですが
おひとつ質問がございます。
①GetLastError についてなのですが
特に、GetLastError()をEAに書き込んでいなくても
エラーがでると。
2016.08.11 21:39:59.950 2015.07.23 15:44 OrderSend error 130
とエラーが返ってくるのですが、
GetLastErrorを書き込むのと、書きこまないのではなに違うのでしょうか?
お盆お休み中とおもうのですが、
また、あけたときにでも返信をいただけると
とてもうれしいです。
私は土日祝日、盆暮れ正月関係なしなので大丈夫です!(笑)
確かにエラーが出るとMT4がエラーコードをログに書いてくれているので、GetLastErrorでエラーコードを出力する必要はありません。
そこで今回はエラーコードではなくエラーメッセージを出力するようにしてみました。
(GetLastErrorを使わないと、プログラムからはエラーコードを取得できません。)
エラーコードを調べればすぐに原因はわかるのですが、メッセージを出しておけばコードを調べなくても、たいてい原因がわかると思います。
(日本語で表示すればもっと良いのですが、MT4の場合、文字化けの恐れがあるので安易に日本語が使えません;;)
また、Alertにしたり、メールでエラーを送信したい場合などはGetLastErrorを使ってエラーコードを通知することは有効な手段になります。
(メール通知については今後やる予定です)