接下來我們要說關於錯誤處理的部分,順便記錄一些交易資訊,而像是timeouts、connection errors這些錯誤有時候重試訂單時就會自動排除。
首先我們要Include <ErrorDescription.mqh>檔案來獲取錯誤描述,而我個人的預設檔裡沒有這個,所以我是從github找來的:
https://github.com/zephyrrr/MLEA/blob/master/MQL5/Include/Utils/ErrorDescription.mqh
這個能讓我們獲得錯誤的描述字串,可以方便我們整理錯誤。
定義一個列舉值,來確定訂單是否成功
enum TradeResult {
Trade_Success,
Trade_Error,
Trade_Retry,
};
創建CheckReturnCode來檢查返回碼,根據獲得的返回代碼,從列舉值中返回常量。
int CheckReturnCode(uint pRetCode){
int status;
switch(pRetCode){
case TRADE_RETCODE_REQUOTE:
case TRADE_RETCODE_CONNECTION:
case TRADE_RETCODE_PRICE_CHANGED:
case TRADE_RETCODE_TIMEOUT:
case TRADE_RETCODE_PRICE_OFF:
case TRADE_RETCODE_REJECT:
case TRADE_RETCODE_ERROR:
status = Trade_Retry;
break;
case TRADE_RETCODE_DONE:
case TRADE_RETCODE_DONE_PARTIAL:
case TRADE_RETCODE_PLACED:
case TRADE_RETCODE_NO_CHANGES:
status = Trade_Success;
break;
default: status = Trade_Error;
}
return(status);
}
這邊先檢查了一些顯示機要成功或是非錯誤訊息的情況,若都不屬於這些則會返回Trade_Error
前面有提到可以使用重試來避免超時或連接錯誤,讓我們能更專注的面對更重要的錯誤。
int checkCode = 0;
int retryCount = 0;
int maxRetryCount = 3;
int retryDelay = 3000;//延遲3秒
do
{
OrderSend(request,result);
checkCode = CheckReturnCode(result.retcode);
if(checkCode == Trade_Success)break;
else if(checkCode == Trade_Error){
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("Open market order: Error ",result.retcode," - ",errDesc);
break;
}
else{
Sleep(retryDelay);
retryCount++;
}
}
while (retryCount < maxRetryCount);
if(retryCount >= maxRetryCount)
{
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("Max retries exceeded: Error ",result.retcode," - ",errDesc);
}
這邊先設定最大重試次數為3,延遲為三秒。使用Do-while因為可以先循環一次,若為成功下單則直接跳出,錯誤則藉由ErrorDescription中的函數顯示錯誤訊息,當重試次數超過3時亦回傳錯誤訊息。
在前面我們創好了排解錯誤,最後一步則是要將整個訂單訊息輸出到交易日誌中,方便辨識錯誤出自哪一個訂單,確定那些訂單是沒問題的。而在輸出之前我們要先創建一個函數來獲取訂單類型。
string CheckOrderType(ENUM_ORDER_TYPE pType)
{
string orderType;
if(pType == ORDER_TYPE_BUY) orderType = "buy";
else if(pType == ORDER_TYPE_SELL) orderType = "sell";
else if(pType == ORDER_TYPE_BUY_STOP) orderType = "buy stop";
else if(pType == ORDER_TYPE_BUY_LIMIT) orderType = "buy limit";
else if(pType == ORDER_TYPE_SELL_STOP) orderType = "sell stop";
else if(pType == ORDER_TYPE_SELL_LIMIT) orderType = "sell limit";
else if(pType == ORDER_TYPE_BUY_STOP_LIMIT) orderType = "buy stop limit";
else if(pType == ORDER_TYPE_SELL_STOP_LIMIT) orderType = "sell stop limit";
else orderType = "invalid order type";
return(orderType);
}
string orderType = CheckOrderType(pType);
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Print("Open ",orderType," order #",result.deal,": ",result.retcode," - ",errDesc,", Volume: ",result.volume,", Price: ",result.price,", Bid: ",result.bid,", Ask: ",result.ask);
因為這個OpenPosition函數不是以void宣告,所以必須回傳boolean值。
if(checkCode == Trade_Success) return(true);
else return(false);