Skip to content

Commit

Permalink
Merge tag 'v2.013.1' into v3.006-dev-new
Browse files Browse the repository at this point in the history
* tag 'v2.013.1':
  Final fix for orders are opened instead of being closed for both MT4 and MT5 (fixes GH-707)
  Fix for orders are opened instead of being closed (GH-707)
  Order: Improves error handling
  Order:Trade: Improves error handling
  Workaround for closing order conditions after orders are loaded from active pool (GH-705)
  Adds close retry counter (GH-703)
  • Loading branch information
kenorb committed Apr 27, 2024
2 parents 4214899 + a723dd7 commit cfe9343
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 29 deletions.
1 change: 1 addition & 0 deletions Order.enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enum ENUM_ORDER_PARAM {
*/
enum ENUM_ORDER_PROPERTY_CUSTOM {
ORDER_PROP_NONE = 0,
ORDER_PROP_CLOSE_TRIES, // Close tries.
ORDER_PROP_COMMISSION, // Commission.
ORDER_PROP_LAST_ERROR, // Last error code.
ORDER_PROP_PRICE_CLOSE, // Close price.
Expand Down
34 changes: 19 additions & 15 deletions Order.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -928,14 +928,16 @@ class Order : public SymbolInfo {
MqlTradeResult _result = {0};
_request.action = TRADE_ACTION_DEAL;
_request.comment = _comment != "" ? _comment : odata.GetReasonCloseText();
_request.deviation = orequest.deviation;
_request.symbol = orequest.symbol;
_request.type = NegateOrderType(orequest.type);
_request.type_filling = GetOrderFilling(orequest.symbol);
_request.deviation = orequest.deviation > 0 ? orequest.deviation : 40;
_request.magic = odata.Get<ulong>(ORDER_MAGIC);
_request.symbol = odata.Get(ORDER_SYMBOL);
_request.type = NegateOrderType(odata.Get<ENUM_ORDER_TYPE>(ORDER_TYPE));
_request.type_filling = GetOrderFilling(odata.Get(ORDER_SYMBOL));
_request.position = odata.Get<ulong>(ORDER_PROP_TICKET);
_request.price = SymbolInfo::GetCloseOffer(orequest.type);
_request.price = SymbolInfo::GetCloseOffer(odata.Get<ENUM_ORDER_TYPE>(ORDER_TYPE));
_request.volume = odata.Get<double>(ORDER_VOLUME_CURRENT);
Order::OrderSend(_request, oresult, oresult_check);
odata.IncCloseTries(); // Increases number of closures tries.
switch (oresult.retcode) {
case TRADE_RETCODE_DONE:
// For now, sets the current time.
Expand All @@ -952,18 +954,19 @@ class Order : public SymbolInfo {
// break;
case TRADE_RETCODE_INVALID:
default:
odata.Set<unsigned int>(ORDER_PROP_LAST_ERROR, fmax(oresult.retcode, oresult_check.retcode));
if (OrderSelect()) {
Refresh(true);
if (!IsClosed()) {
ologger.Error(StringFormat("Failed to send order request %d! Error: %d (%s)", oresult.deal,
oresult_check.retcode, oresult_check.comment),
__FUNCTION_LINE__);
if (logger.GetLevel() >= V_DEBUG) {
ologger.Error(
StringFormat("Failed to send order request %u for position %d! Error: %d (%s)", oresult.request_id,
_request.position, fmax(oresult.retcode, oresult_check.retcode), oresult_check.comment),
__FUNCTION_LINE__);
if (ologger.GetLevel() >= V_DEBUG) {
ologger.Debug(StringFormat("Failed request: %s", ToString()), __FUNCTION_LINE__);
}
}
}
odata.Set<unsigned int>(ORDER_PROP_LAST_ERROR, fmax(oresult.retcode, oresult_check.retcode));
}
return false;
}
Expand All @@ -975,6 +978,7 @@ class Order : public SymbolInfo {
* Returns true if successful.
*/
bool OrderCloseDummy(ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") {
odata.IncCloseTries(); // Increases number of closures tries.
odata.Set(ORDER_PROP_LAST_ERROR, ERR_NO_ERROR);
odata.Set(ORDER_PROP_PRICE_CLOSE, SymbolInfoStatic::GetCloseOffer(symbol, odata.Get<ENUM_ORDER_TYPE>(ORDER_TYPE)));
odata.Set(ORDER_PROP_REASON_CLOSE, _reason);
Expand Down Expand Up @@ -1177,9 +1181,9 @@ class Order : public SymbolInfo {
}
static bool OrderSend(const MqlTradeRequest &_request, MqlTradeResult &_result, MqlTradeCheckResult &_result_check,
color _color = clrNONE) {
_result.retcode = TRADE_RETCODE_ERROR;
#ifdef __MQL4__
// Convert Trade Request Structure to function parameters.
_result.retcode = TRADE_RETCODE_ERROR;
if (_request.position > 0) {
if (_request.action == TRADE_ACTION_SLTP) {
if (Order::OrderModify(_request.position, _request.price, _request.sl, _request.tp, _request.expiration,
Expand Down Expand Up @@ -1288,6 +1292,8 @@ class Order : public SymbolInfo {
long OrderSend() {
long _result = -1;
odata.ResetError();
oresult.retcode = ERR_NO_ERROR;
oresult_check.retcode = ERR_NO_ERROR;
#ifdef __MQL4__
_result = Order::OrderSend(orequest.symbol, // Symbol.
orequest.type, // Operation.
Expand Down Expand Up @@ -2606,14 +2612,12 @@ class Order : public SymbolInfo {
*/
bool ProcessConditions(bool _refresh = false) {
bool _result = true;
if (IsOpen(_refresh) && ShouldCloseOrder()) {
#ifdef __MQL__
// _reason += StringFormat(": %s", EnumToString(oparams.cond_close));
#endif
if (IsOpen(_refresh) && (odata.Get<long>(ORDER_PROP_CLOSE_TRIES) > 0 || ShouldCloseOrder())) {
ARRAY(DataParamEntry, _args);
DataParamEntry _cond = ORDER_REASON_CLOSED_BY_CONDITION;
ArrayPushObject(_args, _cond);
_result &= Order::ExecuteAction(ORDER_ACTION_CLOSE, _args);
odata.IncCloseTries();
}
return _result;
}
Expand Down
12 changes: 11 additions & 1 deletion Order.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ struct OrderData {
ENUM_ORDER_TYPE_TIME type_time; // Lifetime (the order validity period).
ENUM_ORDER_REASON reason; // Reason or source for placing an order.
ENUM_ORDER_REASON_CLOSE reason_close; // Reason or source for closing an order.
unsigned int close_tries; // Number of close tries.
unsigned int last_error; // Last error code.
double volume_curr; // Current volume.
double volume_init; // Initial volume.
Expand All @@ -262,7 +263,8 @@ struct OrderData {
string symbol; // Symbol of the order.
public:
OrderData()
: magic(0),
: close_tries(0),
magic(0),
position_id(0),
position_by_id(0),
ticket(0),
Expand Down Expand Up @@ -296,6 +298,8 @@ struct OrderData {
T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) {
double _tick_value = SymbolInfoStatic::GetTickValue(symbol);
switch (_prop_name) {
case ORDER_PROP_CLOSE_TRIES:
return (T)close_tries;
case ORDER_PROP_COMMISSION:
return (T)commission;
case ORDER_PROP_LAST_ERROR:
Expand Down Expand Up @@ -498,9 +502,15 @@ struct OrderData {
return "???";
}
// Setters.
void IncCloseTries() {
close_tries++;
}
template <typename T>
void Set(ENUM_ORDER_PROPERTY_CUSTOM _prop_name, T _value) {
switch (_prop_name) {
case ORDER_PROP_CLOSE_TRIES:
close_tries = (unsigned int)_value;
return;
case ORDER_PROP_COMMISSION:
commission = (double)_value;
return;
Expand Down
45 changes: 32 additions & 13 deletions Trade.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
bool _result = false;
unsigned int _last_error = _order.Get<unsigned int>(ORDER_PROP_LAST_ERROR);
logger.Link(_order.GetLogger());
_order.GetLogger().SetLevel(tparams.Get<ENUM_LOG_LEVEL>(TRADE_PARAM_LOG_LEVEL));
Ref<Order> _ref_order = _order;
switch (_last_error) {
case 69539:
Expand Down Expand Up @@ -802,6 +803,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
if (_order.IsOpen()) {
// @todo: _order.IsPending()?
_result &= orders_active.Set(_order.Get<long>(ORDER_PROP_TICKET), _order_ref);
logger.Link(_order.GetLogger());
_order.GetLogger().SetLevel(tparams.Get<ENUM_LOG_LEVEL>(TRADE_PARAM_LOG_LEVEL));
} else {
_result &= orders_history.Set(_order.Get<long>(ORDER_PROP_TICKET), _order_ref);
}
Expand All @@ -819,7 +822,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
if (OrderStatic::MagicNumber() == _magic_no) {
unsigned long _ticket = OrderStatic::Ticket();
Ref<Order> _order = new Order(_ticket);
orders_active.Set(_ticket, _order);
OrderLoad(_order.Ptr());
}
}
}
Expand Down Expand Up @@ -864,13 +867,18 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
order_last = _order;
} else {
logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get<unsigned long>(ORDER_PROP_LAST_ERROR));
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
} else {
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand All @@ -896,16 +904,20 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
order_last = _order;
} else {
logger.Error("Error while closing order!", __FUNCTION_LINE__,
StringFormat("Code: %d", _order.Ptr().Get<unsigned long>(ORDER_PROP_LAST_ERROR)));
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
order_last = _order;
}
} else {
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand Down Expand Up @@ -934,14 +946,19 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
order_last = _order;
} else {
logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get<unsigned long>(ORDER_PROP_LAST_ERROR));
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
}
} else {
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand All @@ -968,14 +985,15 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
Math::Compare(_order.Ptr().Get<T>((E)_prop2), _value2, _op)) {
if (!_order.Ptr().OrderClose(_reason, _comment)) {
#ifndef __MQL4__
// @fixme: GH-571.
// @fixme: GH-571 & GH-706.
logger.Info(__FUNCTION_LINE__, _order.Ptr().ToString());
#endif
// @fixme: GH-570.
// logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR));
logger.Warning("Issue with closing the order!", __FUNCTION_LINE__);
ResetLastError();
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
order_last = _order;
_closed++;
Expand All @@ -984,6 +1002,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand Down

0 comments on commit cfe9343

Please sign in to comment.